/*	JSClassSuger v0.1 <http://code.google.com/p/js-class-sugar/> 
	is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> 
*/

/**
 * @author tonylua@sina.com
 */
 
(function(window, document, Array, undefined){
	var namespace = function(ns_string)
		{
		    var parts = ns_string.split('.'),
		        parent = window,
		        i;
		    
		    if (parts[0] === "window")
		        parts = parts.slice(1);
		    for (i = 0; i < parts.length; i += 1) {
		        if (typeof parent[parts[i]] === "undefined")
		            parent[parts[i]] = {};
		        
		        parent = parent[parts[i]];
		    }
		    return parent;
		},
		delegate = function()
		{
			var func = arguments[0],
				thisObj = arguments[1],
				params = Array.prototype.slice.call(arguments, 2);
			if (params.length == 1 && params[0] instanceof Array)
				params = params[0];
			return function(){func.apply(thisObj, params);};
		},
		isDef = function(obj)
		{
			return !((typeof obj === 'undefined') || obj === null);
		},
		copyProperties = function(target, source, isOverride)
		{
			isOverride = isDef(isOverride) ? isOverride : true;
			for (var k in source)
				if ( isOverride || ( !isOverride && !target.hasOwnProperty(k) ) )
					target[k] = source[k];
		},
		extend = function(subClass, baseClass, members, isOverride)
		{
			function inheritance(){}
			inheritance.prototype = baseClass.prototype;
			var oldPorto = subClass.prototype||{};
			subClass.prototype = new inheritance();
			copyProperties(subClass.prototype, oldPorto);
			oldPorto = null;
			subClass.prototype.constructor = subClass;
			subClass.baseConstructor = baseClass;
			subClass.superClass = baseClass.prototype;
			if ( isDef(members) ) copyProperties(subClass.prototype, members, isOverride);
		};
		
	
	var ClassBuilder = (function(){
		var builder = null,
			clsbdrId = 0,
			rmPrefix = function(str){
				return str.replace(/^window(\.|$)/, '');
			},
			fullPkg = function(str){
				return ('window.'+str).replace(/\.+$/, '');
			},
			getPkg = function(pkgPath){
				namespace(pkgPath);
				pkgPath = fullPkg(pkgPath);
				var base = window,
					parts = pkgPath.split('.'),
					len = parts.length,
					i = 0;
				while(i<len) base = base[parts[i++]];
				return base;
			},
			refClass = function(clsName, cls){
				var pkg = clsName.split('.'),
				clsName = pkg.pop();
				pkg = pkg.join('.');
				getPkg(pkg)[clsName] = cls;
			},
			eachName = function(str, callback){
				for (var i=0, arr=str.split(/\s*,\s*/g), len=arr.length; i<len; i++)
					callback.call(null, rmPrefix(arr[i]));
			};
		/* config
			@name:			String className
			@constructor:	Object constructor
			@properties:	Object pubVars
			@methods:		Object pubFuncs
		*/
		builder = function(config){
			var __msId = null,
				__bdrRef = this,
				clz = null;
				
			if (!config.name) throw '[ClassBuilder] need a name param';
			else config.name = rmPrefix(config.name);
			
			clz = function()
			{
				__msId = clsbdrId++;
				
				var cc = config.constructor;
				if (cc)
				{
					var cArr = [cc],
						i = 0,
						len = 0;
					
					if (__bdrRef.__ext)
						for(i=__bdrRef.__ext.length-1; i>=0; i--)
							cArr.push( __bdrRef.__ext[i] );
					
					var constArgs = Array.prototype.slice.call(arguments, 0);
					
					for (i=cArr.length-1;i>=0;i--)
					{
						try{
							cArr[i].apply(this, constArgs);
						}catch(ex){}
					}
					
					for (var k in this)
						if (typeof this[k] == 'function')
							clz.prototype[k] = this[k];
					
					//__bdrRef.__cargs = constArgs;
				}
			};
			
			clz.toString = function(){return '[class '+ fullPkg(config.name)+']';};
			clz.prototype = {
				toString: function(){
					return '[class '+ fullPkg(config.name)+'] instance #' + __msId;
				},
				$_getClassId: function(){
					return __msId;
				},
				$_cOverride: function(){
					if (!clz.baseConstructor) return null;
					var orargs = Array.prototype.slice.call(arguments, 0);
					clz.baseConstructor.apply(this, orargs);
				},
				$_mOverride: function(methodName){
					if (!clz.baseConstructor) return null;
					var orargs = Array.prototype.slice.call(arguments, 1);
					clz.baseConstructor.prototype[methodName].apply(this, orargs);
				}
			};
			
			if (config.properties)
				copyProperties(clz.prototype, config.properties);
			if (config.methods)
				copyProperties(clz.prototype, config.methods);
			
			refClass(config.name, clz);
			
			this.clz = clz;
			return this;
		}; //end of builder
		builder.toString = function(){return '[class ClassBuilder]';};
		builder.prototype = {
			'extends': function(/*string|...classes*/superClasses)
			{
				var clz = this.clz,
					bdr = this,
					doExtend = function(superClz){
						if (!bdr.__ext) bdr.__ext = [];
						bdr.__ext.push(superClz);
						extend(clz, superClz, null, false);
					};
				try{
					if (typeof superClasses == 'string')
						eachName(superClasses, function(name){
							var pkg = name.split('.'),
								clsObj = null;
							name = pkg.pop();
							pkg = pkg.join('.');
							clsObj = getPkg(pkg)[name];
							doExtend(clsObj);
						});
					else 
						for (var i=0,len=arguments.length; i<len; i++)
							doExtend(arguments[i]);
				}catch(ex){
					throw '[ClassBuilder] extends error! ' + ex.toString();
				}
				return this;
			},
			'implements': function(/*string|...classes*/interfaceClasses)
			{
				if (!this.__itf) this.__itf = [];
				try{
					if (typeof interfaceClasses == 'string')
					{
						var bdr = this;
						eachName(interfaceClasses, function(name){
							var iclz = Interface.Pool[name];
							bdr.__itf = iclz;
						});
					}
					else			
						for (var i=0,len=arguments.length; i<len; i++)
							this.__itf[i] = arguments[i];
				}catch(ex){
					throw '[ClassBuilder] implements error! ' + ex.toString();
				}
				return this;
			},
			build: function()
			{
				if (this.__itf)
					for (var i=0,len=this.__itf.length; i<len; i++)
						Interface.ensure(this.clz, this.__itf[i]);
				return this.clz;
			}
		};
		return builder;
	}());
	
	
	var Interface = function (name, methods) {
	    if (arguments.length != 2)
	        throw new Error("[Interface] the interface length is bigger than 2");
	    this.Name = name;
	    this.Method = [];
	    for (var i = 0; i < methods.length; i++){
	    	if(typeof methods[i]!== 'string')
	    		throw new Error("[Interface] the method name is not string");
	    	this.Method.push(methods[i]);
	    }
	    Interface.Pool[name] = this;
	};
	Interface.Pool = {};
	Interface.ensure = function (object) {
	    if (arguments.length < 2)
	        throw new Error("[Interface] there is not Interface or the instance");
	    for (var i = 1; i < arguments.length; i++) {
	        var interface1 = arguments[i];
	        if (interface1.constructor !== Interface)
	            throw new Error("[Interface] the argument is not interface");
	        
	        object = object.prototype;
	        for (var j = 0; j < interface1.Method.length; j++) {
	            var method = interface1.Method[j];
	            if (!object[method] || typeof object[method] !== 'function')
	                throw new Error("[Interface] you instance doesn't implement the interface "+ interface1.Name +" of method \"" + method + "\"");
	        }
	    }
	};
	
	window.ClassBuilder = ClassBuilder;
	window.Interface = Interface;
}(window, document, Array));


function $_package(pkgPath, pkgDefine)
{
	var defSet = [pkgDefine],
		i, len;
	
	if (arguments.length>2)
		defSet = defSet.concat( Array.prototype.slice.call(arguments, 1) );
	
	for (i=0,len=defSet.length; i<len; i++)
	{
		var def = defSet[i]
			builder = new ClassBuilder({
			name: [pkgPath,def.name].join('.'),
			constructor: def.constructor
		});
		if (def['extends'])
			builder['extends'].call(builder, def['extends']);
		if (def['implements'])
			builder['implements'].call(builder, def['implements']);
		builder.build();
	}
}
function $_Class(clsName, clsDefine)
{
	return {
		name: clsName,
		constructor: clsDefine.$_,
		'extends': clsDefine.$_extends,
		'implements': clsDefine.$_implements
	}
}